package com.hnd.springframerwork.beans.factory.support;

import cn.hutool.core.bean.BeanException;
import cn.hutool.core.bean.BeanUtil;
import com.hnd.springframerwork.beans.PropertyValue;
import com.hnd.springframerwork.beans.PropertyValues;
import com.hnd.springframerwork.beans.factory.config.AutowireCapableBeanFactory;
import com.hnd.springframerwork.beans.factory.config.BeanDefinition;
import com.hnd.springframerwork.beans.factory.config.BeanPostProcessor;
import com.hnd.springframerwork.beans.factory.config.BeanReference;

import java.lang.reflect.Constructor;

/**
 * 负责创建bean实例
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    Object createBean(String beanName, BeanDefinition beanDefinition) {
        return createBean(beanName, beanDefinition, null);
    }

    @Override
    Object createBean(String beanName, BeanDefinition beanDefinition, Object... args) {
       //创建bean
        Object beanInstance = createBeanInstance(beanName, beanDefinition, args);
         //填充属性
        applyPropertyValues(beanInstance, beanDefinition);

        //执行bean的初始化方法和beanPostProcessor 的前置和后置处理方法
        Object bean= initializeBean(beanName, beanInstance, beanDefinition);
        return bean;
    }


    Object createBeanInstance(String beanName, BeanDefinition beanDefinition, Object... args) {
        if (args == null||args.length==0) {
            return instantiationStrategy.instantiate(beanDefinition, null, args);
        }

        Class beanClazz = beanDefinition.getBeanClazz();
        Constructor constructorToUse = null;
        for (Constructor constructor : beanClazz.getDeclaredConstructors()) {
            if (constructor.getParameterTypes().length == args.length) {
                constructorToUse = constructor;
                break;
            }
        }
        return instantiationStrategy.instantiate(beanDefinition, constructorToUse, args);
    }

    void applyPropertyValues(Object bean,BeanDefinition beanDefinition) {

        PropertyValue[] properties = beanDefinition.getPropertyValues().getProperties();

        for (PropertyValue pv : properties) {
            Object value = pv.getValue();
            if (value instanceof BeanReference) {
                value = getBean(((BeanReference) value).getName());
            }
            BeanUtil.setFieldValue(bean,pv.getName(),value);
        }
    }

    private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
        //1. 执行beanPostProcessor before 处理
        Object wrapperBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

        //未完成

        // 2. 执行 BeanPostProcessor After 处理

        wrapperBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        return wrapperBean;
    }

    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeanException {
        Object result = existingBean;
        for (BeanPostProcessor postProcessor : getBeanPostProcessors()) {
            Object current = postProcessor.postProcessBeforeInitialization(result, beanName);
            if (null == current) {
                return result;
            }
            result = current;
            return result;
        }

        return result;
    }

    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeanException {
        Object result = existingBean;
        for (BeanPostProcessor postProcessor : getBeanPostProcessors()) {
            Object current = postProcessor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
}
